package com.code.test.dance;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * https://blog.51cto.com/u_16099226/7161354
 *
 * https://blog.csdn.net/qq_45888932/article/details/124111106
 *
 * 有三个线程A,B,C， 三个线程轮流打印出1,2,3；其中线程A只能打印1， 线程B只能打印2， 线程C只能打印3
 */
public class MultiThreadPrint123 {


    public static void main(String[] args) {

        PrintThread tt = new PrintThread();
        new Thread(() -> tt.printA(), "A").start();

        new Thread(() -> tt.printB(), "B").start();

        new Thread(() -> tt.printC(), "C").start();

//        PrintWithCondition pp = new PrintWithCondition();
//        new Thread(() -> {
//            while (true) {
//                pp.printA();
//            }
//
//        }, "A").start();
//        new Thread(() -> {
//            while (true) {
//                pp.printB();
//            }
//
//        }, "B").start();
//        new Thread(() -> {
//            while (true) {
//                pp.printC();
//            }
//
//        }, "C").start();
    }
}

class PrintWithCondition {

    private Lock lock = new ReentrantLock();
    private int flag = 1;

    private Condition con1 = lock.newCondition();
    private Condition con2 = lock.newCondition();
    private Condition con3 = lock.newCondition();

    public void printA() {
        lock.lock();
        try {
            while (flag != 1) {
                //等待
                con1.await();
            }
            System.out.println(Thread.currentThread().getName() + ":1");
            flag = 2;
            //通知
            con2.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printB() {
        lock.lock();
        try {
            while (flag != 2) {
                //等待
                con2.await();
            }
            System.out.println(Thread.currentThread().getName() + ":2");
            flag = 3;
            //通知
            con3.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printC() {
        lock.lock();
        try {
            while (flag != 3) {
                //等待
                con3.await();
            }
            System.out.println(Thread.currentThread().getName() + ":3");
            System.out.println("-----------------------------------");
            flag = 1;
            //通知
            con1.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

/**
 * 利用双重检测+ volatile可见性
 * https://blog.csdn.net/qq_45888932/article/details/124111106
 */
class PrintThread {

    private volatile int flag = 1;

    public void printA() {
        while (true) {
            if (flag == 1) {
                synchronized (this) {
                    if (flag == 1) {
                        System.out.println(Thread.currentThread().getName() + ":1");
                        flag = 2;
                    }
                }
            }
        }
    }

    public void printB() {
        while (true) {
            if (flag == 2) {
                synchronized (this) {
                    if (flag == 2) {
                        System.out.println(Thread.currentThread().getName() + ": 2");
                        flag = 3;
                    }
                }
            }
        }
    }

    public void printC() {
        while (true) {
            if (flag == 3) {
                synchronized (this) {
                    if (flag == 3) {
                    System.out.println(Thread.currentThread().getName() + ": 3");
                    System.out.println("-----------------------------------");
                    flag = 1;
                    }
                }
            }
        }
    }
}


